package com.example.demo.utils;

import com.example.demo.config.JwtProperties;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.KeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.RedisTemplate;

@Component
public class JwtUtils {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    private static final String BLACKLIST_KEY = "jwt:blacklist";

    @Autowired
    private JwtProperties jwtProperties;
    
    private SecretKey secretKey;

    @PostConstruct
    public void init() {
        if (jwtProperties == null) {
            throw new IllegalStateException("JwtProperties must be configured");
        }
        this.secretKey = generateKeyFromText(jwtProperties.getSecretKeyText());
    }

    private SecretKey generateKeyFromText(String text) {
        try {
            // Use PBKDF2 to generate a fixed key from the text
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec spec = new PBEKeySpec(text.toCharArray(), 
                "salt".getBytes(), 65536, 256);
            return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "HmacSHA256");
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate secret key", e);
        }
    }

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return Jwts.builder()
                .claims(claims)
                .subject(username)
                .issuedAt(new Date())
                .expiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 1000))
                .signWith(secretKey)
                .compact();
    }

    public Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .verifyWith(secretKey)
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }

    public String getUsernameFromToken(String token) {
        return getClaimsFromToken(token).getSubject();
    }

    public boolean validateToken(String token) {
        try {
            getClaimsFromToken(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public void invalidateToken(String token) {
        if (token != null && !token.isBlank()) {
            // 将token加入黑名单，并设置过期时间
            redisTemplate.opsForValue().set(
                BLACKLIST_KEY + ":" + token, 
                "1", 
                jwtProperties.getExpiration(), 
                TimeUnit.SECONDS
            );
        }
    }

    public boolean isTokenBlacklisted(String token) {
        if (token == null || token.isBlank()) {
            return false;
        }
        return redisTemplate.hasKey(BLACKLIST_KEY + ":" + token);
    }
}
